package com.lmabbe.oauth.filter;

import com.lmabbe.common.global.constant.GlobalConstant;
import com.lmabbe.oauth.config.CustomAuthenticationEntryPoint;
import org.apache.dubbo.rpc.RpcContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author lmabbe
 */
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {

    /**
     * 认证如果失败由该端点进行响应
     */
    private final AuthenticationEntryPoint authenticationEntryPoint = new CustomAuthenticationEntryPoint();
    @Autowired
    private TokenStore tokenStore;

    /**
     * 具体的认证方法  匿名访问不要携带token
     * 有些逻辑自己补充 这里只做基本功能的实现
     */
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
        // 如果已经通过认证
        RpcContext.getContext()
                .setAttachment(GlobalConstant.SYSTEM.FROM_CLIENT, request.getHeader(GlobalConstant.SYSTEM.FROM_CLIENT))
                .setAttachment(GlobalConstant.SYSTEM.TENANT_ID, request.getHeader(GlobalConstant.SYSTEM.TENANT_ID));
        if (SecurityContextHolder.getContext().getAuthentication() != null) {
            chain.doFilter(request, response);
            return;
        }
        // 获取 header 解析出 jwt 并进行认证 无token 直接进入下一个过滤器  因为  SecurityContext 的缘故 如果无权限并不会放行
        String header = request.getHeader(GlobalConstant.SYSTEM.AUTHORIZATION);
        if (StringUtils.hasText(header) && header.startsWith(GlobalConstant.SYSTEM.AUTHENTICATION_PREFIX)) {
            String token = header.replace(GlobalConstant.SYSTEM.AUTHENTICATION_PREFIX, "");
            if (StringUtils.hasText(token)) {
                try {
                    authenticationTokenHandle(token, request);
                } catch (AuthenticationException e) {
                    authenticationEntryPoint.commence(request, response, new BadCredentialsException("token is bad"));
                }
            } else {
                // 带安全头 没有带token
                authenticationEntryPoint.commence(request, response, new AuthenticationCredentialsNotFoundException("token is not found"));
            }

        }
        chain.doFilter(request, response);
    }

    private void authenticationTokenHandle(String token, HttpServletRequest request) {
        OAuth2Authentication oAuth2Authentication = tokenStore.readAuthentication(token);
        SecurityContextHolder.getContext().setAuthentication(oAuth2Authentication);

    }
}
